(function(angular) {
  'use strict';
  angular.module('fs.waf').run(main);

  main.$inject = [
    '$rootScope',
    '$timeout',
    '$location',
    '$state',
    '$stateParams',
    '$translate',
    '$q',
    '$window',
    '$document',
    '$ocLazyLoad',
    '$parse',
    'Constants',
    'loggerFactory',
    'ajaxServiceFactory',
    'storageService',
    'StorageConstants',
    'modalService',
    'commonService',
    'routerService',
    'ChartJs'
  ];
  function main(
    $rootScope,
    $timeout,
    $location,
    $state,
    $stateParams,
    $translate,
    $q,
    $window,
    $document,
    $ocLazyLoad,
    $parse,
    Constants,
    loggerFactory,
    ajaxServiceFactory,
    storageService,
    StorageConstants,
    modalService,
    commonService,
    routerService,
    ChartJs
  ) {
    var log = loggerFactory.getLogger('fs.waf');
    upgradeLocalStorageData();
    $rootScope.showSiteCode = true;
    $rootScope.loggerFactory = loggerFactory;
    $rootScope.$state = $state;
    $rootScope.$stateParams = $stateParams;
    $rootScope.getBizDate = function() {
      return $rootScope.site.bizDate;
    };
    $rootScope.getEodDate = function() {
      return $rootScope.site.eodDate;
    };
    $rootScope.stopEventPropagation = function($event) {
      $event.preventDefault();
      $event.stopPropagation();
    };
    $rootScope.removePageDescription = function() {
      if (angular.isFunction($rootScope.pageDescriptionWtcher)) {
        $rootScope.pageDescriptionWtcher();
      }
      delete $rootScope.pageDescription;
    };
    $rootScope.setPageDescription = function(p) {
      if ($rootScope.pageDescriptionWatcher) {
        $rootScope.pageDescriptionWatcher();
      }
      if (angular.isFunction(p)) {
        $rootScope.pageDescriptionWtcher = $rootScope.$watch(p, function(description) {
          $rootScope.pageDescription = description;
        });
      } else {
        $rootScope.pageDescription = p;
      }
    };
    $rootScope.copyPageIdTooltip = 'label.copy.pageid';
    if (!$rootScope.dataType || !$rootScope.dataKey) {
      $rootScope.disabledAuditOrNote = true;
    } else {
      $rootScope.disabledAuditOrNote = false;
    }
    $rootScope.I18N = {
      language: 'en_US'
    };
    $rootScope.setLogLevel = function() {
      loggerFactory.setLevel($rootScope.app.settings.logLevel, '*');
    };
    $rootScope.backTo = function() {
      var state = storageService.getLastHistory() || [];
      var lastUrl = state.fromUrl || [];
      if ($rootScope.$state.current.name == lastUrl) {
        storageService.popHistory();
        state = storageService.getLastHistory() || [];
        lastUrl = state.fromUrl || [];
      }
      var lastParams = state.fromParams || [];
      if (lastUrl) {
        lastParams._isBack = true;
        $rootScope.go(lastUrl, lastParams);
      }
    };
    $rootScope.go = function(state, params, disableUnloadCheck) {
      if (!state) {
        return;
      }
      var togo = function() {
        var toState = routerService.parseState(state);
        var toParams = {
          params: angular.merge(
            {
              __originalState: $state.current.name,
              __state: toState
            },
            params || {}
          )
        };
        if ($rootScope.$uibModalInstance) {
          $rootScope.$uibModalInstance.dismiss();
        }
        $state.go(toState, toParams, {
          location: true,
          // inherit: false,
          reload: toState
        });
      };
      if (disableUnloadCheck) {
        togo();
      } else {
        $rootScope.unloadCheck().then(function() {
          togo();
        }, angular.noop);
      }
    };
    $rootScope.copySuccess = function() {
      $rootScope.copyPageIdTooltip = 'label.copy.copied';
      $timeout(function() {
        $rootScope.copyPageIdTooltip = 'label.copy.pageid';
      }, 2000);
    };
    $rootScope.defaultMouseEvent = function($event) {
      $event.preventDefault();
      $event.stopPropagation();
    };
    //audit
    $rootScope.viewAuditTooltip = 'label.audit.viewaudit';
    $rootScope.viewAudit = function() {
      var params = {
        dataType: $rootScope.dataType,
        dataKey: $rootScope.dataKey
      };
      modalService.openCustomDialogs({
        title: 'dialog.title.audit-list',
        dialogsModule: 'audit.popuplist',
        size: [850, 500],
        params: params,
        btnCallback: {
          ok: function(qaChoiceCtrl) {}
        }
      });
    };
    //adminNote
    $rootScope.createNoteTooltip = 'label.note.create';
    $rootScope.createNote = function() {
      var dataType = $rootScope.dataType,
        isForTxn = false,
        title,
        dialogsModule,
        url;
      title = 'dialog.title.note';
      dialogsModule = 'note.popupCreate';
      url = 'note/create.do';
      var params = {
        dataType: dataType,
        dataKey: $rootScope.dataKey,
        dataStatus: $rootScope.dataStatus,
        serviceCode: $rootScope.serviceCode,
        taskId: $rootScope.taskId
      };
      modalService.openCustomDialogs({
        title: title,
        dialogsModule: dialogsModule,
        custormerTemplateUrl: 'pti/template/modal/custormerOfColseAndSaveBtn.html',
        params: params,
        size: [850, 510],
        btnCallback: {
          ok: function(returnObj) {
            var ajaxService = ajaxServiceFactory.buildAjaxService({
              createSubmit: {
                url: url,
                method: 'post'
              }
            });
            var defer = $q.defer();
            ajaxService.createSubmit({ note: returnObj }).then(function(response) {
              defer.resolve(response);
            });
            return defer.promise;
          }
        }
      });
    };
    $rootScope.removeAuditOrNoteParams = function() {
      delete $rootScope.dataType;
      delete $rootScope.dataKey;
      delete $rootScope.dataStatus;
      //delete $rootScope.serviceCode;
      delete $rootScope.taskId;
      $rootScope.disabledAuditOrNote = true;
    };
    $rootScope.saveAuditAndNoteParams = function(toState, toParams) {
      var serviceCode, stateArray, params;
      if (!toState) {
        return;
      }
      stateArray = toState.split('_');
      if (stateArray[1] == 'app') {
        serviceCode = stateArray[2];
      }
      if (toParams && toParams.params) {
        params = toParams.params;
        $rootScope.initAuditOrNoteParams(params.dataType || params.currentDataType, params.dataKey || params.primaryKey, params.dataStatus, serviceCode);
      } else {
        $rootScope.initAuditOrNoteParams('', '', '', serviceCode);
      }
    };
    $rootScope.initAuditOrNoteParams = function(dataType, dataKey, dataStatus, serviceCode, taskId) {
      $rootScope.dataType = dataType;
      $rootScope.dataKey = dataKey;
      $rootScope.dataStatus = dataStatus;
      $rootScope.serviceCode = serviceCode;
      $rootScope.taskId = taskId;
      if (!$rootScope.dataType || !$rootScope.dataKey) {
        $rootScope.disabledAuditOrNote = true;
      } else {
        $rootScope.disabledAuditOrNote = false;
      }
    };
    $rootScope.removeFormState = function() {
      delete $rootScope._isUnloadCheck;
      delete $rootScope._formName;
      delete $rootScope._isUnloadCheck;
      delete $rootScope._formScope;
      delete $rootScope._formDataKey;
      delete $rootScope._formFields;
      delete $rootScope._formDataHashCode;
    };
    $rootScope.initFormState = function(scope, formDataKey, formName) {
      if ($rootScope._formName && $rootScope._formName != formName) {
        return;
      }
      $rootScope._formName = formName;
      if (('mustUnloadCheckForm' != formName && formDataKey.indexOf('.searchCriteria') >= 0) || !scope.fsGridLayoutController || !scope.fsGridLayoutController.fsConfig) {
        return;
      }
      $rootScope._isUnloadCheck = true;
      $rootScope._formScope = $rootScope._formScope || {};
      $rootScope._formScope[formDataKey] = scope;
      $rootScope._formDataKey = $rootScope._formDataKey || [];
      $rootScope._formDataKey.push(formDataKey);
      $rootScope._formFields = $rootScope._formFields || [];
      $rootScope._formFields[formDataKey] = $rootScope._formFields[formDataKey] || {};
      $rootScope._formFields[formDataKey] = angular.merge($rootScope._formFields[formDataKey], getPageFormFields(scope.fsGridLayoutController.fsConfig));
      $rootScope._formDataHashCode = $rootScope._formDataHashCode || {};
      $rootScope._formDataHashCode[formDataKey] = commonService.hash(getPageFormData(scope.$eval(formDataKey), $rootScope._formFields[formDataKey]));
      $window.onbeforeunload = isFormChanged;
    };
    $rootScope.initFormTableState = function(scope, tableOptions, formName) {
      if ($rootScope._formName && $rootScope._formName != formName) {
        return;
      }
      if (!tableOptions.data || !angular.isString(tableOptions.data) || !tableOptions.columnDefs) {
        return;
      }
      //fixed issue for open audit then close then click the other menu.
      if (tableOptions.data.indexOf('.searchCriteria') >= 0) {
        return;
      }
      $rootScope._isUnloadCheck = true;
      $rootScope._formName = formName;
      $rootScope._formScope = $rootScope._formScope || {};
      $rootScope._formScope[tableOptions.data] = scope;
      $rootScope._formDataKey = $rootScope._formDataKey || [];
      $rootScope._formDataKey.push(tableOptions.data);
      $rootScope._formFields = $rootScope._formFields || [];
      $rootScope._formFields[tableOptions.data] = getPageFormFields(tableOptions.columnDefs);
      $rootScope._formDataHashCode = $rootScope._formDataHashCode || {};
      $rootScope._formDataHashCode[tableOptions.data] = commonService.hash(getPageFormData(scope.$eval(tableOptions.data), $rootScope._formFields[tableOptions.data]));
      $window.onbeforeunload = isFormChanged;
    };
    $rootScope.disableUnloadCheck = function() {
      delete $rootScope._isUnloadCheck;
      $window.onbeforeunload = null;
    };
    $rootScope.unloadCheck = function() {
      var defer = $q.defer();
      if (!$rootScope._isUnloadCheck || !$rootScope._formScope) {
        $rootScope._isUnloadCheck = true;
        $window.onbeforeunload = isFormChanged;
        defer.resolve(true);
      } else if (hasChanged()) {
        modalService.openConfirmDialogs({
          messages: ['Are you sure to leave this page?'],
          btnCallback: {
            ok: function(response) {
              defer.resolve(true);
            },
            close: function(response) {
              defer.reject(false);
            }
          }
        });
      } else {
        defer.resolve(true);
      }
      return defer.promise;
    };
    $rootScope.buildAuthService = function(authorizationConfig) {
      var authorizationServices = {};
      angular.forEach(authorizationConfig, function(value, key) {
        authorizationServices[key] = {
          url: value,
          method: 'post'
        };
      });
      return ajaxServiceFactory.buildAjaxService(authorizationServices);
    };
    $rootScope.showLog = function() {
      var logContent = storageService.getLog();
      var logs = [];
      angular.forEach(
        logContent,
        function(value, key) {
          this.push(value.content);
        },
        logs
      );
      modalService.openLogDialogs({
        title: 'label.title.log',
        messages: logs.join('\n')
      });
    };
    $rootScope.saveHistory = function(event, toState, toParams, fromState, fromParams) {
      if (toParams.params && toParams.params._isBack) {
        storageService.popHistory();
      }
      if (fromState.name && (!toParams.params || !toParams.params._isBack) && !isIgnoreHistory(fromState)) {
        if (fromParams.params && fromParams.params.isIgnoreHistory) {
          return;
        }
        storageService.saveHistory({
          pageId: $rootScope.pageId,
          fromUrl: fromState.name,
          fromParams: fromParams.params,
          toUrl: toState.name,
          toParams: toParams.params
        });
      }
    };
    $rootScope.loadResource = function(resources) {
      if (resources) {
        storageService.setItemToSession(Constants.SESSION_I18N_RESOURES, resources);
        $rootScope.$emit(Constants.NOTIFY_CHANGE_LANGUAGE);
      }
    };
    $rootScope.$on(Constants.NOTIFY_CHANGE_LANGUAGE, function($event, param) {
      $event.preventDefault();
      $event.stopPropagation();
      if (param) {
        angular.extend($rootScope.I18N, param);
      }
      if ($rootScope.I18N.language) {
        $translate.use($rootScope.I18N.language).then(function() {
          $translate.refresh($rootScope.I18N.language);
        });
      }
    });
    $rootScope.$on(Constants.NOTIFY_REDIRECT, function($event, param) {
      $event.preventDefault();
      $event.stopPropagation();
      if (Constants.WELCOME_URL == param.url) {
        if ($rootScope.user && $rootScope.menus && 'EXPORTER' == $rootScope.user.companyType) {
          var menuItems = $rootScope.menus,
            welcomeMenuConfig;
          for (var i = 0; i < menuItems.length; i++) {
            var menuConfig = menuItems[i];
            if (menuConfig && Constants.SELLER_WELCOME_MENU_DISPLAY_NAME == menuConfig.displayName) {
              welcomeMenuConfig = menuConfig;
              break;
            }
          }
          $scope.go(Constants.SELLER_WELCOME_URL, welcomeMenuConfig);
        } else {
          $scope.go(Constants.WELCOME_URL);
        }
      } else if (param.url) {
        window.location.href = param.url;
      }
    });
    $rootScope.$on(Constants.NOTIFY_UNAUTHORIZED, function($event, response) {
      $event.preventDefault();
      $event.stopPropagation();
      $rootScope.disableUnloadCheck();
      storageService.clearAllFromSession();
      // storageService.clearAllFromLocal();
      delete $rootScope.user;
      delete $rootScope.site;
      delete $rootScope.menus;
      if (!$stateParams.params || ($stateParams.params.__originalState != 'signon' && $state.$current.name != 'signon')) {
        $rootScope.$emit(Constants.NOTIFY_REDIRECT, {
          url: 'signon.do'
        });
      }
    });
    $rootScope.$on(Constants.NOTIFY_PAGE_NOT_FOUNT, function($event, response) {
      $event.preventDefault();
      $event.stopPropagation();
      $rootScope.disableUnloadCheck();
      $rootScope.go('error.E404', response);
    });
    $rootScope.$on(Constants.NOTIFY_SYSTEM_ERROR, function($event, response) {
      $event.preventDefault();
      $event.stopPropagation();
      $rootScope.disableUnloadCheck();
      $rootScope.go('error.E500', response.errorMessages);
    });
    $rootScope.$on(Constants.NOTIFY_CUSTOMER_ERROR, function($event, response) {
      $event.preventDefault();
      $event.stopPropagation();
      if (response.conflictErrorMessage) {
        modalService.openErrorDialogs({
          messages: [response.conflictErrorMessage],
          blocked: true,
          size: [415, 115],
          btnCallback: {
            close: function(response) {
              $rootScope.go('poi.workflow.wfTxn.list');
            }
          }
        });
      } else {
        modalService.openErrorDialogs({
          messages: response.errorMessages,
          blocked: true
        });
      }
    });

    ChartJs.Chart.defaults.global.defaultFontFamily = "'Interstate', Arial, sans-serif";
    ChartJs.Chart.scaleService.updateScaleDefaults('linear', {
      ticks: {
        min: 0
      }
    });
    ChartJs.Chart.defaults.global.multiTooltipTemplate = '<%if (datasetLabel){%><%=datasetLabel%>: <%}%><%= value %>';
    ChartJs.Chart.defaults.global.tooltips.mode = 'label';
    ChartJs.Chart.defaults.global.elements.line.borderWidth = 1;
    ChartJs.Chart.defaults.global.elements.arc.borderWidth = 1;
    ChartJs.Chart.defaults.global.elements.rectangle.borderWidth = 1;
    ChartJs.Chart.defaults.global.legend.display = false;
    // ChartJs.Chart.defaults.global.elements.line.backgroundColor = 'transparent';

    // write text plugin
    ChartJs.Chart.pluginService.register({
      id: 'drawDoughnutCenterText',
      afterUpdate: function(chartController) {
        var helpers = ChartJs.Chart.helpers,
          globalConfig,
          ctx,
          fontStyle,
          fontFamily,
          fontSize,
          maxFontSize,
          maxText,
          datas,
          center1,
          center2;
        var centers = chartController.config.options.elements.center;
        if (centers) {
          globalConfig = ChartJs.Chart.defaults.global;
          ctx = chartController.chart.ctx;

          fontStyle = helpers.getValueOrDefault(centers[0].fontStyle, globalConfig.defaultFontStyle);
          fontFamily = helpers.getValueOrDefault(centers[0].fontFamily, globalConfig.defaultFontFamily);

          if (centers[0].fontSize) {
            fontSize = centers[0].fontSize;
          } else {
            // figure out the best font size, if one is not specified
            ctx.save();
            fontSize = helpers.getValueOrDefault(centers[0].minFontSize, 1);
            maxFontSize = helpers.getValueOrDefault(centers[0].maxFontSize, 256);
            maxText = helpers.getValueOrDefault(centers[0].text, centers[0].text);
            do {
              ctx.font = helpers.fontString(fontSize, fontStyle, fontFamily);
              var textWidth = ctx.measureText(maxText).width;
              if (textWidth < chartController.innerRadius * 2 && fontSize < maxFontSize) {
                fontSize += 1;
              } else {
                fontSize -= 1;
                break;
              }
            } while (true);
            ctx.restore();
          }
          centers[0].font = helpers.fontString(fontSize, fontStyle, fontFamily);
          centers[0].fontSize = fontSize;
          centers[0].fillColor = helpers.getValueOrDefault(centers[0].fontColor, globalConfig.defaultFontColor);

          fontStyle = helpers.getValueOrDefault(centers[1].fontStyle, globalConfig.defaultFontStyle);
          fontFamily = helpers.getValueOrDefault(centers[1].fontFamily, globalConfig.defaultFontFamily);

          if (centers[1].fontSize) {
            fontSize = centers[1].fontSize;
          } else {
            // figure out the best font size, if one is not specified
            ctx.save();
            fontSize = helpers.getValueOrDefault(centers[1].minFontSize, 1);
            maxFontSize = helpers.getValueOrDefault(centers[1].maxFontSize, 256);
            maxText = helpers.getValueOrDefault(centers[1].text, centers[1].text);
            do {
              ctx.font = helpers.fontString(fontSize, fontStyle, fontFamily);
              var textWidth = ctx.measureText(maxText).width;
              if (textWidth < chartController.innerRadius * 2 && fontSize < maxFontSize) {
                fontSize += 1;
              } else {
                fontSize -= 1;
                break;
              }
            } while (true);
            ctx.restore();
          }
          centers[1].font = helpers.fontString(fontSize, fontStyle, fontFamily);
          centers[1].fontSize = fontSize;
          centers[1].fillColor = helpers.getValueOrDefault(centers[1].fontColor, globalConfig.defaultFontColor);

          chartController.center = {
            center1: centers[0],
            center2: centers[1],
            onClick: chartController.config.options.elements.center.onClick
          };
        }
      },
      beforeDraw: function(chartController) {
        var helpers = ChartJs.Chart.helpers,
          ctx,
          config,
          centerX,
          centerY,
          datas,
          total = 0;
        var centers = chartController.config.options.elements.center;
        if (chartController.center) {
          ctx = chartController.chart.ctx;
          centerX = (chartController.chartArea.left + chartController.chartArea.right) / 2;
          centerY = (chartController.chartArea.top + chartController.chartArea.bottom) / 1.8;
          chartController.center.x = centerX;
          chartController.center.y = centerY;
          ctx.save();
          ctx.textAlign = 'center';
          ctx.textBaseline = 'middle';
          ctx.font = helpers.fontString(chartController.center.center1.fontSize, chartController.center.center1.fontStyle, chartController.center.center1.fontFamily);
          ctx.fillStyle = chartController.center.center1.fillColor;
          ctx.fillText(chartController.center.center1.text, chartController.center.x, centerY - chartController.center.center1.fontSize - 3);
          ctx.font = helpers.fontString(chartController.center.center2.fontSize, chartController.center.center2.fontStyle, chartController.center.center2.fontFamily);
          ctx.fillStyle = chartController.center.center2.fillColor;
          ctx.fillText(chartController.center.center2.text, centerX, centerY);
          ctx.restore();
          if (chartController.center.onClick && !chartController.center.addEventListener) {
            chartController.center.addEventListener = true;
            chartController.chart.canvas.addEventListener(
              'mousemove',
              (function(chartController, config) {
                return function(event) {
                  var x, y;
                  x = event.layerX;
                  y = event.layerY;
                  if (
                    x >= config.x - chartController.innerRadius &&
                    x <= config.x + chartController.innerRadius &&
                    y <= config.y + chartController.innerRadius &&
                    y >= config.y - chartController.innerRadius
                  ) {
                    event.target.parentElement.style.cursor = 'pointer';
                    config.inLink = true;
                  } else {
                    event.target.parentElement.style.cursor = '';
                    config.inLink = false;
                  }
                };
              })(chartController, chartController.center),
              false
            );
            chartController.chart.canvas.addEventListener('click', clickHandlerFactory(chartController, chartController.center), false);
          }
        }
        function clickHandlerFactory(chartController, config) {
          return function(event) {
            if (config.inLink) {
              config.onClick(chartController, config, event);
            }
          };
        }
      }
    });

    function getPageFormData(pageModel, fields) {
      var getter,
        setter,
        formaData = {};
      if (fields && pageModel) {
        if (angular.isArray(pageModel)) {
          formaData = [];
          angular.forEach(pageModel, function(model, index) {
            formaData[index] = getPageFormData(model, fields);
          });
        } else {
          angular.forEach(fields, function(field, key) {
            getter = $parse(field);
            setter = getter.assign;
            try {
              if (getter(pageModel) !== undefined) {
                setter(formaData, getter(pageModel));
              }
            } catch (e) {}
          });
        }
      } else {
        formaData = pageModel;
      }
      return formaData;
    }
    function getPageFormFields(pageConfig) {
      var fields;
      if (!pageConfig) {
        return fields;
      }
      angular.forEach(pageConfig, function(column) {
        if (column.field && (!column.cellTemplate || column.cellTemplate.indexOf('fs-grid-config="row.entity"') != -1)) {
          fields = fields || {};
          fields[column.field] = column.field;
        }
      });
      angular.forEach(pageConfig.gridConfigs, function(grid) {
        if (grid.model) {
          fields = fields || {};
          fields[grid.model] = grid.model;
        }
      });
      angular.forEach(pageConfig.formConfigs, function(form) {
        angular.forEach(form.gridConfigs, function(grid) {
          if (grid.model) {
            fields = fields || {};
            fields[grid.model] = grid.model;
          }
        });
      });
      return fields;
    }
    function isFormChanged($event) {
      if (hasChanged()) {
        ($event || $window.event).returnValue = 'Are you sure to leave this page?';
        return 'Are you sure to leave this page?';
      } else {
        return undefined;
      }
    }
    function hasChanged() {
      var i = 0,
        scope,
        dataKey,
        pageData,
        fields,
        changed;
      if (!$rootScope._formDataKey) {
        return false;
      }
      for (i = 0; i < $rootScope._formDataKey.length; i++) {
        dataKey = $rootScope._formDataKey[i];
        scope = $rootScope._formScope[dataKey];
        fields = $rootScope._formFields[dataKey];
        pageData = scope.$eval(dataKey);
        changed = commonService.hash(getPageFormData(pageData, fields)) != $rootScope._formDataHashCode[dataKey];
        if (changed) {
          return changed;
        }
      }
      return false;
    }
    function isIgnoreHistory(state) {
      var pattern = /(?:.*\.(?:create)|(?:createContinue)|(?:createReject)|(?:update)|(?:updateContinue)|(?:updateReject)|(?:delete)|(?:deleteReject))/;
      return pattern.test(state.name);
    }
    function upgradeLocalStorageData() {
      var lastVersionInfo = storageService.getItemFromLocal('SYS_VERSION');

      //TODO versionInfo undefine
      // if (!lastVersionInfo || lastVersionInfo.version != versionInfo.version) {
      //   // write the logic here when the data of local storage need upgrade
      //   storageService.setItemToLocal('SYS_VERSION', versionInfo);
      // }
    }
  }
})(angular);
